import { h } from "koishi"
import fsp from "fs/promises"
import { fileURLToPath } from "url"

/// <reference types="koishi-plugin-ffmpeg" />
/// <reference types="koishi-plugin-silk" />

export const name = "discord-audio-encode"

export const inject = { required: ["ffmpeg"], optional: ["silk"] }

/** @param {import("koishi").Context} ctx */
export function apply(ctx) {
  ctx.platform("discord").on("before-send", async session => {
    if (!h.select(session.elements, "audio").length) return
    session.elements = await h.transformAsync(session.elements, {
      async audio(attrs) {
        if (!attrs.src) return true
        // qqnt seems to have a delay saving audio messages to disk, here’s a dirty fix
        if (attrs.src.startsWith("file:") && attrs.src.includes("nt_data/Ptt"))
          await ctx.sleep(1500)
        try {
          /** @type {Uint8Array | ArrayBuffer} */
          let buf
          if (attrs.src.startsWith("file:"))
            buf = await fsp.readFile(fileURLToPath(attrs.src))
          else buf = await ctx.http.get(attrs.src, { responseType: "arraybuffer" })
          const f = ctx.ffmpeg.builder()
          if (ctx.silk && ctx.silk.isSilk(buf)) {
            buf = (await ctx.silk.decode(buf, 48000)).data
            f.inputOption("-ar", "48000", "-f", "s16le")
          }
          const newBuf = await f
            .input(Buffer.from(buf))
            .outputOption("-c", "libopus", "-f", "ogg")
            .run("buffer")
          // wrap the audio in <message> to force it to be sent separately;
          //   adapter does not seem to handle this well
          // force filename to "audio.ogg", which would otherwise be "file.oga"
          //   causing the audio to be sent as an attached file because discord is dumb
          return h("message", h.audio(newBuf, "audio/ogg", { file: "audio.ogg" }))
        } catch (err) {
          ctx.logger.warn(err)
          return true
        }
      },
    })
  })
}
